using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using OpenComposite.EII.Repository;
using OpenComposite.Base.Collections;

namespace OpenComposite.EII.Designer.BRules
{
	[ToolboxItem(false)]
	public partial class UCIFExpression : UserControl
	{
		#region Initialization
		public UCIFExpression()
		{
			InitializeComponent();

			init();
		}

		private void init()
		{
			this.SuspendLayout();
			try {
				// add IFSymbol.ConditionPartTypes to cmbType
				cmbType.BeginUpdate();
				try {
					cmbType.Items.Clear();
					foreach ( IFSymbol.ConditionPartType t in Enum.GetValues(typeof(IFSymbol.ConditionPartType)) ) {
						//if ( t != IFSymbol.ConditionPartType.ProcessVariable )
							cmbType.Items.Add(t);
					}
					cmbType.SelectedIndex = 0;
				} finally {
					cmbType.EndUpdate();
				}
				// add True / False to cmbValueBool
				cmbValueBool.BeginUpdate();
				try {
					cmbValueBool.Items.Clear();
					cmbValueBool.Items.AddRange(new object[] { true, false });
				} finally {
					cmbValueBool.EndUpdate();
				}

				//layoutPnl.Controls.Add(pnlValueMain, 1, 0);
				pnlValueMain.Height = 21;
				pnlValueMain.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;

				this.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
				this.Height = 21;
			} finally {
				this.ResumeLayout(true);
			}
		}
		#endregion

		#region Public Members

		#region Properties
		[Category("UCIFExpression")]
		[DefaultValue(IFSymbol.ConditionPartType.Boolean)]
		public IFSymbol.ConditionPartType Type
		{
			get {
				if ( cmbType.SelectedItem is IFSymbol.ConditionPartType )
					return (IFSymbol.ConditionPartType)cmbType.SelectedItem;
				else
					return IFSymbol.ConditionPartType.Boolean;
			}
			set { cmbType.SelectedItem = value; }
		}
		
		[Browsable(false)]
		public IServiceProvider ServiceProvider
		{
			get { return _serviceProvider; }
			set { _serviceProvider = value; }
		}
		[Browsable(false)]
		public object Value
		{
			get
			{
				switch ( this.Type ) {
					case IFSymbol.ConditionPartType.Boolean:
						return cmbValueBool.SelectedItem;
					case IFSymbol.ConditionPartType.Variable:
						return _noun;
					case IFSymbol.ConditionPartType.ProcessVariable:
						return _processVar;
					case IFSymbol.ConditionPartType.Rule:
						return _rule;
					case IFSymbol.ConditionPartType.RuleConstant:
						return _constant;
					case IFSymbol.ConditionPartType.Number:
						return txtValueNumber.Text;
					case IFSymbol.ConditionPartType.String:
						return txtValueString.Text;
					case IFSymbol.ConditionPartType.DateTime:
						return GetDateTimeValue();
					case IFSymbol.ConditionPartType.ResultString:
						return cmbValueRuleResult.SelectedItem;
				}
				return null;
			}
			set
			{
				if ( this.Value == value )
					return;

				if ( value is bool ) {
					this.Type = IFSymbol.ConditionPartType.Boolean;
					cmbValueBool.SelectedItem = value;
				} else if ( value is string ) {
					this.Type = IFSymbol.ConditionPartType.String;
					txtValueString.Text = (string)value;
				} else if ( value is int || value is long || value is double || value is decimal ) {
					this.Type = IFSymbol.ConditionPartType.Number;
					txtValueNumber.Text = value.ToString();
				} else if ( value is DateTime ) {
					this.Type = IFSymbol.ConditionPartType.DateTime;
					dateValue.Value = (DateTime)value;
					timeValue.Value = (DateTime)value;
				} else if ( value is Noun ) {
					this.Type = IFSymbol.ConditionPartType.Variable;
					_noun = value as Noun;
					showNoun();
				} else if ( value is WorkflowField ) {
					this.Type = IFSymbol.ConditionPartType.ProcessVariable;
					_processVar = value as WorkflowField;
					showNoun();
				} else if ( value is RepositoryBusinessRule ) {
					this.Type = IFSymbol.ConditionPartType.Rule;
					_rule = value as RepositoryBusinessRule;
					showRule();
				} else if ( value is RuleConstant ) {
					this.Type = IFSymbol.ConditionPartType.RuleConstant;
					_constant = value as RuleConstant;
					showRuleConstant();
				} else {
					this.Type = IFSymbol.ConditionPartType.Boolean;
					cmbValueBool.SelectedItem = true;
				}
				OnValueChanged();
			}
		}

		public int WorkflowID
		{
			get { return _idWorkflow; }
			set { _idWorkflow = value; }
		}

		#endregion

		#region Events
		[Category("UCIFExpression")]
		public event EventHandler ConditionPartTypeChanged = null;
		[Category("UCIFExpression")]
		public event EventHandler ValueChanged = null;
		#endregion

		#region Methods

		public void SetValue(IFSymbol.ConditionPartType type, object value)
		{
			this.SuspendLayout();
			try {
				object oldValue = this.Value;
				this.Type = type;
				showPleaseSelect();
				switch ( type ) {
					case IFSymbol.ConditionPartType.Variable:
						if ( value is Noun )
							_noun = (Noun)value;
						else if ( value is int )
							_noun = RepositoryService.GetItem(ItemType.Noun, (int)value, false) as Noun;
						if ( _noun != null )
							showNoun();
						break;
					case IFSymbol.ConditionPartType.ProcessVariable:
						if ( value is WorkflowField )
							_processVar = (WorkflowField)value;
						else if ( value is int )
							_processVar = RepositoryService.GetItem<WorkflowField>((int)value);
						if ( _processVar != null )
							showProcessVariable();
						break;
					case IFSymbol.ConditionPartType.Rule:
						if ( value is RepositoryBusinessRule )
							_rule = (RepositoryBusinessRule)value;
						else if ( value is int )
							_rule = RepositoryService.GetItem(ItemType.BRule, (int)value, false) as RepositoryBusinessRule;
						if ( _rule != null )
							showRule();
						break;
					case IFSymbol.ConditionPartType.RuleConstant:
						if ( value is RuleConstant )
							_constant = (RuleConstant)value;
						else if ( value is int )
							_constant = RepositoryService.GetItem(ItemType.RuleConstant, (int)value, false) as RuleConstant;
						if ( _constant != null )
							showRuleConstant();
						break;
					case IFSymbol.ConditionPartType.Boolean:
						if ( value is bool )
							cmbValueBool.SelectedItem = (bool)value;
						else
							cmbValueBool.SelectedItem = true;
						break;
					case IFSymbol.ConditionPartType.Number:
						txtValueNumber.Text = value.ToString();
						break;
					case IFSymbol.ConditionPartType.String:
						txtValueString.Text = value.ToString();
						break;
					case IFSymbol.ConditionPartType.DateTime:
						if ( value is string ) {
							DateTime dt;
							DateTime.TryParse(value.ToString(), out dt);
							setDateTime(dt);
						} if ( value is DateTime ) {
							setDateTime((DateTime)value);
						} else {
							DateTime dt = DateTime.Now;
							setDateTime(new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0));
						}
						break;
					case IFSymbol.ConditionPartType.ResultString:
						int index = cmbValueRuleResult.Items.IndexOf(value.ToString());
						cmbValueRuleResult.SelectedIndex = index;
						break;
				}
				if ( oldValue == this.Value ) {
					OnValueChanged();
				}
			} finally {
				this.ResumeLayout(true);
			}
		}
		public void SetResultStrings(string results)
		{
			string[] resultarray = results.Split(';', ',');
			if ( resultarray != null && resultarray.Length > 0 ) {
				cmbValueRuleResult.BeginUpdate();
				try {
					cmbValueRuleResult.Items.Clear();
					cmbValueRuleResult.Items.AddRange(resultarray);
				} finally {
					cmbValueRuleResult.EndUpdate();
				}
			}
		}

		public bool GetBooleanValue()
		{
			return (bool)cmbValueBool.SelectedItem;
		}
		public string GetStringValue()
		{
			return txtValueString.Text;
		}
		public long GetLongValue()
		{
			long l;
			long.TryParse(txtValueNumber.Text, out l);
			return l;
		}
		public decimal GetDecimalValue()
		{
			decimal d;
			decimal.TryParse(txtValueNumber.Text, out d);
			return d;
		}
		public double GetDoubleValue()
		{
			double d;
			double.TryParse(txtValueNumber.Text, out d);
			return d;
		}
		public DateTime GetDateTimeValue()
		{
			DateTime d = dateValue.Value;
			DateTime t = dateValue.Value;
			DateTime dt = new DateTime(d.Year, d.Month, d.Day, t.Hour, t.Minute, t.Second);
			return dt;
		}
		public int GetRuleID()
		{
			if ( _rule != null )
				return _rule.ID;
			else
				return -1;
		}
		public int GetNounID()
		{
			if ( _noun != null )
				return _noun.ID;
			else
				return -1;
		}
		public int GetRuleConstantID()
		{
			if ( _constant != null )
				return _constant.ID;
			else
				return -1;
		}

		public string GetResultString()
		{
			return cmbValueRuleResult.SelectedItem as string;
		}
		#endregion

		#endregion

		#region Protected Members

		#region Properties
		protected RepositoryService RepositoryService
		{
			get { return (RepositoryService)_serviceProvider.GetService(typeof(RepositoryService)); }
		}
		#endregion

		#region Methods
		// new
		protected virtual void OnValueChanged()
		{
			EventHandler tmp = this.ValueChanged;
			if ( tmp != null ) {
				tmp(this, EventArgs.Empty);
			}
		}
		// override
		protected override void OnLoad(EventArgs e)
		{
		}
		#endregion

		#endregion

		#region Private Members

		#region Varibles
		
		private Noun _noun;
		private RepositoryBusinessRule _rule;
		private RuleConstant _constant;
		private WorkflowField _processVar;
		private int _idWorkflow;

		private IServiceProvider _serviceProvider;
		
		#endregion

		#region Methods
		private void setConditionPartType(IFSymbol.ConditionPartType type)
		{
			this.SuspendLayout();
			try {
				bool isBoolean = ( type == IFSymbol.ConditionPartType.Boolean );
				bool isNounRule = ( type == IFSymbol.ConditionPartType.Variable ||
									type == IFSymbol.ConditionPartType.Rule ||
									type == IFSymbol.ConditionPartType.RuleConstant ||
									type == IFSymbol.ConditionPartType.ProcessVariable);
				bool isNumber = ( type == IFSymbol.ConditionPartType.Number );
				bool isString = ( type == IFSymbol.ConditionPartType.String );
				bool isDateTime = ( type == IFSymbol.ConditionPartType.DateTime );
				bool isResultString = ( type == IFSymbol.ConditionPartType.ResultString );

				// set visibility of input fields
				cmbValueBool.Visible = isBoolean;
				pnlValueItem.Visible = isNounRule;
				txtValueNumber.Visible = isNumber;
				txtValueString.Visible = isString;
				pnlValueDateTime.Visible = isDateTime;
				cmbValueRuleResult.Visible = isResultString;

				// set default values
				if ( isBoolean ) {
					cmbValueBool.SelectedIndex = 0;
				} else if ( isDateTime ) {
					DateTime dt = DateTime.Now;
					setDateTime(new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0));
				} else if ( isNounRule ) {
					showPleaseSelect();
				}
			} finally {
				this.ResumeLayout(true);
			}
			// fire changed event
			EventHandler tmp = this.ConditionPartTypeChanged;
			if ( tmp != null ) {
				tmp(this, EventArgs.Empty);
			}
		}

		private void showNoun()
		{
			this.SuspendLayout();
			try {
				if ( _noun == null ) {
					showPleaseSelect();
				} else {
					txtValueItem.Text = _noun.Display;
					txtValueItem.ForeColor = SystemColors.ControlText;
				}
			} finally {
				this.ResumeLayout(true);
			}
		}
		private void showProcessVariable()
		{
			this.SuspendLayout();
			try {
				if ( _processVar == null ) {
					showPleaseSelect();
				} else {
					txtValueItem.Text = _processVar.Display;
					txtValueItem.ForeColor = SystemColors.ControlText;
				}
			} finally {
				this.ResumeLayout(true);
			}
		}
		private void showRule()
		{
			this.SuspendLayout();
			try {
				if ( _rule == null ) {
					showPleaseSelect();
				} else {
					txtValueItem.Text = _rule.Display;
					txtValueItem.ForeColor = SystemColors.ControlText;
				}
			} finally {
				this.ResumeLayout(true);
			}
		}
		private void showRuleConstant()
		{
			this.SuspendLayout();
			try {
				if ( _constant == null ) {
					showPleaseSelect();
				} else {
					txtValueItem.Text = _constant.Display;
					txtValueItem.ForeColor = SystemColors.ControlText;
				}
			} finally {
				this.ResumeLayout(true);
			}
		}
		private void showPleaseSelect()
		{
			this.SuspendLayout();
			try {
				txtValueItem.Text = "Please select a " + this.Type.ToString() + ".";
				txtValueItem.ForeColor = SystemColors.GrayText;
			} finally {
				this.ResumeLayout(true);
			}
		}

		private void setDateTime(DateTime dt)
		{
			this.SuspendLayout();
			try{
				dateValue.Value = dt;
				timeValue.Value = dt;
			} finally {
				this.ResumeLayout(true);
			}
		}
		#endregion

		#region Event Handlers

		private void cmbType_SelectedIndexChanged(object sender, EventArgs e)
		{
			setConditionPartType((IFSymbol.ConditionPartType)cmbType.SelectedItem);
		}

		private void btnValueNounRule_Click(object sender, EventArgs e)
		{
			if ( this.Type != IFSymbol.ConditionPartType.Variable && this.Type != IFSymbol.ConditionPartType.Rule &&
				 this.Type != IFSymbol.ConditionPartType.RuleConstant && this.Type != IFSymbol.ConditionPartType.ProcessVariable )
				throw new Exception("Impossible Type.");

			using ( Forms.FormSelectRepositoryEx frm =
				new OpenComposite.EII.Forms.FormSelectRepositoryEx(this.ServiceProvider, this.Type == IFSymbol.ConditionPartType.ProcessVariable? _idWorkflow:-1) ) {
				frm.AllowChangeDomain = true;
				frm.AllowChangeType = false;
				frm.AllowCreateNewItem = true;

				if ( this.Type == IFSymbol.ConditionPartType.Variable )
					frm.AllowedTypes = new ItemType[] { ItemType.Noun };
				else if ( this.Type == IFSymbol.ConditionPartType.Rule )
					frm.AllowedTypes = new ItemType[] { ItemType.BRule };
				else if ( this.Type == IFSymbol.ConditionPartType.ProcessVariable )
					frm.AllowedTypes = new ItemType[] { ItemType.Workflow_Field };
				else
					frm.AllowedTypes = new ItemType[] { ItemType.RuleConstant };

				frm.DomainID = Global.Status.CurrentDomainId;
				frm.RepositoryID = Global.Status.CurrentRepositoryId;
				frm.ShowAllDomains = true;
				frm.ShowAllFolders = false;
				frm.MultiSelect = false;
				if ( frm.ShowDialog() == DialogResult.OK ) {
					List<IRepositoryItem> lst = frm.GetSelectedItems();
					if ( lst.Count == 0 )
						return;
					_noun = lst[0] as Noun;
					_rule = lst[0] as RepositoryBusinessRule;
					_constant = lst[0] as RuleConstant;
					_processVar = lst[0] as WorkflowField;
					if ( _noun != null ) {
						showNoun();
					} else if ( _rule != null ) {
						showRule();
					} else if ( _constant != null ) {
						showRuleConstant();
					} else if ( _processVar != null ) {
						showProcessVariable();
					} else {
						showPleaseSelect();
					}
					OnValueChanged();
				}
			}
		}

		#endregion

		#endregion
	}

}
